﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Text;
using System.Windows.Forms;

namespace Remote_Commander
{
    public partial class frm_output : Form
    {
        //Member variables
        CommandParameters commandParameters;
        SaveFileDialog saveDialog = new SaveFileDialog();

        string arguments;
        string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\Remote Commander";
        string fileName = @"\computers.txt";
        string fullFilePath;
        delegate void SetTextCallback(string text);

        //Create a new process
        Process psexec = new Process();
        int procID;

        //Constructor
        public frm_output(CommandParameters parameters)
        {
            InitializeComponent();
            this.FormClosing += new FormClosingEventHandler(frm_output_FormClosing);

            //Store the parameters passed to this class
            commandParameters = parameters;

            //Create a text file that we can target PSEXEC toward
            createFileList();

            //Set some startup information options
            psexec.StartInfo.FileName = @"Resources\PsExec.exe";
            psexec.StartInfo.Arguments = constructArguments();
            psexec.StartInfo.CreateNoWindow = true;
            psexec.StartInfo.UseShellExecute = false;
            psexec.StartInfo.RedirectStandardOutput = true;
            psexec.StartInfo.RedirectStandardError = true;
            
            //Bind some event handlers
            psexec.OutputDataReceived += new DataReceivedEventHandler(psexec_OutputDataReceived);
            psexec.ErrorDataReceived += new DataReceivedEventHandler(psexec_ErrorDataReceived);

            //Start PSEXEC
            psexec.Start();

            procID = psexec.Id;

            //Begin asynchronously reading the output and error streams
            psexec.BeginOutputReadLine();
            psexec.BeginErrorReadLine();

        }

        //Kill the PSEXEC process if it still exists when the form is closed
        void frm_output_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                Process proc = Process.GetProcessById(procID);

                proc.Kill();
            }
            catch
            {

            }
        }
        
        //Updates the text box with output from PSEXEC
        void SetText(string text)
        {
            //Checks whether or not the target control requires Invokation
            //If so, this method uses a delegate to call itself via the Invoke method
            if (txt_output.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                Invoke(d, new object[] { text });
            }
            else
            {
                txt_output.Text += text + "\r\n";
                txt_output.Select(txt_output.Text.Length, 0);
                txt_output.ScrollToCaret();
            }
        }

        //Error output event handler for PSEXEC
        void psexec_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                SetText(e.Data);
            }
        }

        //Standard output event handler for PSEXEC
        void psexec_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                SetText(e.Data);
            }
        }

        //Construct the command-line arguments for PSEXEC
        private string constructArguments()
        {
            //Determine if we're working with a file on a UNC path or a local drive
            string firstChars = commandParameters.remoteCommand.Substring(0, 2);

            //Start formulating the argument
            arguments = "@\"" + fullFilePath + "\" -u " + commandParameters.domainUsername +
                " -p " + commandParameters.password;

            //Choose to copy the file locally if it is on a UNC path
            if (firstChars == @"\\")
            {
                arguments += " -c -f";
            }
            
            //Add the timeout
            arguments += " -n " + commandParameters.timeoutSeconds;

            //Add the "non-interactive" mode, if necessary
            if (!commandParameters.interactiveCommand)
            {
                arguments += " -d";
            }

            //Add the actual command
            arguments += " \"" + commandParameters.remoteCommand + "\"";

            //Return the whole thing
            return arguments;
        }

        //Create a text file with all the target names
        private void createFileList()
        {
            fullFilePath = folderPath + fileName;

            //Create the folder if it doesn't already exist
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }

            //Delete the file if it already exists
            if (File.Exists(fullFilePath))
            {
                File.Delete(fullFilePath);
            }

            string computerNames = "";

            //Store the list of computers in a string
            foreach (string computer in commandParameters.selectedComputers)
            {
                computerNames += computer + "\r\n";
            }

            //Write the list of computers to the file
            File.WriteAllText(fullFilePath,computerNames);
        }

        //Save the results to a text file
        private void exportResultsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveDialog.Filter = "Text File|*.txt";
            saveDialog.Title = "Export command results";
            saveDialog.OverwritePrompt = true;
            saveDialog.ShowDialog();

            if (!string.IsNullOrEmpty(saveDialog.FileName))
            {
                FileStream fs = (FileStream)saveDialog.OpenFile();

                StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.ASCII);

                sw.Write(txt_output.Text);
                sw.Flush();

                sw.Close();
                fs.Close();

                MessageBox.Show("File saved successfully.");
            }
        }
    }
}
